package com.huatai.bpmn.mapper;

import org.springframework.cglib.beans.BeanCopier;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.UnaryOperator;


/**
 * 属性拷贝
 * @author yxy
 */
public class CGlibMapper {

    //使用缓存提高效率
    private static final ConcurrentHashMap<String, BeanCopier> mapCaches = new ConcurrentHashMap<>();

    /***
     *  通过类复制属性（同一个类其实就是克隆自己）  属性相同才能复制
     * @param source  需要复制的对象
     * @param target 目标类
     * @param <O>
     * @param <T>
     * @return
     */
    public static <O, T> T mapper(O source, Class<T> target) {
        return baseMapper(source, target);
    }



    public static <S, T> List<T> mapperList(List<S> sources, Class<T> target) {
        List<T> list = new ArrayList<>();
        for (S source : sources) {
            T t = baseMapper(source, target);
            list.add(t);
        }
        return list;
    }

    /**
     * 通过类复制属性（同一个类其实就是克隆自己）  属性相同才能复制
     *
     * @param source 需要复制的对象
     * @param target 目标类
     * @param action 支持lambda操作
     * @param <O>
     * @param <T>
     * @return
     */
    public static <O, T> T mapper(O source, Class<T> target, Consumer<T> action) {
        T instance = mapper(source, target);
        action.accept(instance);
        return instance;
    }

    /**
     * 通过类复制属性（同一个类其实就是克隆自己）  属性相同才能复制
     *
     * @param source 需要复制的对象
     * @param target 目标类
     * @param action 支持lambda操作
     * @param <O>
     * @param <T>
     * @return
     */
    public static <O, T> T mapper(O source, Class<T> target, UnaryOperator<T> action) {
        T instance = mapper(source, target);
        return action.apply(instance);
    }



    /***
     * 通过对象复制属性（同一个类其实就是克隆自己）  属性相同才能复制
     * @param source
     * @param target
     * @param <O>
     * @param <T>
     * @return
     */
    public static <O, T> T mapperObject(O source, T target) {
        String baseKey = generateKey(source.getClass(), target.getClass());
        BeanCopier copier;
        if (!mapCaches.containsKey(baseKey)) {
            copier = BeanCopier.create(source.getClass(), target.getClass(), false);
            mapCaches.put(baseKey, copier);
        } else {
            copier = mapCaches.get(baseKey);
        }
        copier.copy(source, target, null);
        return target;
    }

    public static <O, T> T mapperObject(O source, T target, Consumer<T> action) {
        mapperObject(source, target);
        action.accept(target);
        return target;
    }

    public static <O, T> T mapperObject(O source, T target, UnaryOperator<T> action) {
        mapperObject(source, target);
        return action.apply(target);
    }

    private static <O, T> T baseMapper(O source, Class<T> target) {
        String baseKey = generateKey(source.getClass(), target);
        BeanCopier copier;
        if (!mapCaches.containsKey(baseKey)) {
            copier = BeanCopier.create(source.getClass(), target, false);
            mapCaches.put(baseKey, copier);
        } else {
            copier = mapCaches.get(baseKey);
        }
        T instance = null;
        try {
            //需要复制的对象必须要有无参构造器
            instance = target.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        copier.copy(source, instance, null);
        return instance;
    }

    private static String generateKey(Class<?> class1, Class<?> class2) {
        return class1.toString() + class2.toString();
    }


}
